#ifndef _PLATFORM_H_CSEAPI_
#define _PLATFORM_H_CSEAPI_

#include "CseApi/setup.h"

#ifdef CSEAPI_EXPORTS              // Export CSE kernel API
  #define CSE_IMPEXP_IN            CSE_EXPORT
#elif CSE_STATIC_LINK              // Static link CSE kernel
  #define CSE_IMPEXP_IN
#else                              // Import CSE kernel from DLL
  #define CSE_IMPEXP_IN            CSE_IMPORT
#endif
#define CSE_IMPEXP_OUT             CSE_EXPORT

#define CSE_STDCALL                __stdcall

#ifdef _WIN32
  #undef __BIT64SYS__
  
  #ifndef __WINDOWS__
    #define __WINDOWS__
  #endif
#endif

#ifdef _WIN64
  #ifndef _WIN32
    #define _WIN32   // define it for compatibility reasons
  #endif

  #ifndef __BIT64SYS__
    #define __BIT64SYS__
  #endif
  
  #ifndef __WINDOWS__
    #define __WINDOWS__
  #endif
#endif

#if defined(_UNICODE)
  #undef CSE_USE_UNICODE
  #define CSE_USE_UNICODE          1
#else
  #ifndef CSE_USE_UNICODE
    #define CSE_USE_UNICODE        0
  #endif
#endif

#if CSE_USE_UNICODE
  #ifndef _UNICODE
    #define _UNICODE
  #endif
#endif

// CSE API version and feature: V2.0.0.0
#define CSE_API_VERSION            0x02000000
#if !defined(_UNICODE)
  #define CSE_FEATURE_FLAG         0x00000000     // SBCS
#else
  #define CSE_FEATURE_FLAG         0x00000001     // unicode
#endif

#include <limits.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#define CSE_CONCAT(text, post)     text ## post

#ifndef _T
  #if !CSE_USE_UNICODE
    #define _T(x) x
  #else
    #define _T(x)                  CSE_CONCAT(L,x)
  #endif
#endif

#define CHECK_TRUE(b)              Cse_AssertMsg2(b,__LINE__,_T(__FILE__))
#define CHECK_MSG(b,desc)          Cse_AssertMsg(b,desc)
#define WAIT_TO_DO()               throw Cse_WaitToDo(__LINE__,_T(__FILE__))

#ifdef _DEBUG
  #define ASSERT_MSG(b,desc)       Cse_AssertMsg(b,desc)
  #define ASSERT_TRUE(b)           CHECK_TRUE(b)
#else
  #define ASSERT_MSG
  #define ASSERT_TRUE
#endif

#if defined(__WINDOWS__)
  #if defined(_MSC_VER) && _MSC_VER >= 1200   // VC6 and later version
    #pragma warning(disable: 4996)

    #define CSE_EXPORT             __declspec(dllexport)
    #define CSE_IMPORT             __declspec(dllimport)

    typedef char                   TChar;
    typedef wchar_t                TWchar;

    typedef char                   TInt8;
    typedef unsigned char          TUint8;
    typedef short                  TInt16;
    typedef unsigned short         TUint16;
    typedef __int32                TInt32;
    typedef unsigned __int32       TUint32;
    typedef __int64                TInt64;
    typedef unsigned __int64       TUint64;
    typedef float                  TFloat;
    typedef double                 TDouble;

    typedef long                   TLong;
    typedef unsigned long          TUlong;
    typedef bool                   TBool;

    typedef size_t                 TSize_t;  // size_t is standard type in CSE
    typedef void                   TVoid;    // void is standard type in CSE

    #ifdef _UNICODE
      typedef wchar_t              TXchar;
    #else
      typedef char                 TXchar;
    #endif

    // sizeof(TInt) in 32-bits system is 4 bytes, and in 64-bits is 8
    typedef int                    TInt;
    typedef unsigned int           TUint;

    // sizeof(TWint) is 8 bytes both in 32-bits and 64-bits system
    typedef __int64                TWint;

    #define CseLongLongFmtSpec     _T("I64")
  #else
    #error "Compiler not support yet!"
  #endif
#endif

#define CSE_INT_SIZE               sizeof(TInt)

// if sizeof(TInt) != sizeof(void *), error will report at compile time
// CSE system use TInt to hold symbol address also!
struct TInt_same_size_to { int a_pointer: sizeof(TInt) == sizeof(void *); };

// if sizeof(TInt) is not 4 or 8, error will report at compile time
// sizeof(TInt) == 4 is NORMAL_INT_SYS, 8 is LARGE_INT_SYS
struct TInt_must_be { int TInt32_or_TInt64: sizeof(TInt)==4 || sizeof(TInt)==8;};

#ifndef NULL
  #define NULL                     0
#endif

#ifndef SIZE_T_MAX
  #define SIZE_T_MAX               ((size_t) -1)
#endif

#if CSE_USE_ERR_LOG
  #if defined(_UNICODE)
    #define LOG_MSG                wprintf
  #else
    #define LOG_MSG                printf
  #endif
#else
  #define LOG_MSG
#endif

#ifdef _DEBUG
  #define STATIC
  #define LOG_DBG_MSG              LOG_MSG
#else
  #define STATIC                   static
  #define LOG_DBG_MSG
#endif

class TCseException;  // forward declare
extern CSE_IMPEXP_IN void Cse_AssertMsg(int expr, const TXchar *msg);
extern CSE_IMPEXP_IN void Cse_AssertMsg2(int expr, int iLine, const TXchar *sFile);
extern CSE_IMPEXP_IN TCseException Cse_WaitToDo(int line, const TXchar *sFile);

extern CSE_IMPEXP_IN TInt32 READ_FLAG(TInt32 iFlag, int iOffset, int n);
extern CSE_IMPEXP_IN TInt32 MAKE_FLAG(TInt32 iFlag, TInt32 iValue, int iOffset, int n);

#define CUT_FROM                   20051206  // The data CSE V1 first released

#endif
